package butines.core.gui.style;



import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

import butines.core.GameImage;

public class GameFont {

	private Font font;
	private Color[] foreground = { new Color(225, 225, 225), new Color(240, 240, 240) };
	private Color background = Color.BLACK;

	private int vShadow = 1;
	private int hShadow = 1;
	
	private Map<Character, BufferedImage> customChars = new HashMap<Character, BufferedImage>();
	private BufferedImage[] chars = new BufferedImage[256];
	private int lineHeight;
	
	public GameFont(Font font, Color foreground0, Color foreground1, Color background, int hShadow, int vShadow) {
		this.font = font;
		this.foreground[0] = foreground0;
		this.foreground[1] = foreground1;
		this.background = background;
		this.lineHeight = 0;
		this.hShadow = hShadow;
		this.vShadow = vShadow;
		createImageSet();
	}
	
	public GameFont(Font font, Color foreground, Color background) {
		this(font, foreground, foreground, background, 1, 1);
	}
	
	public GameFont(Font font, Color foreground) {
		this(font, foreground, Color.BLACK);
	}
	
	public int getWidth(char ch) {
		BufferedImage img = getImage(ch);
		return (img == null) ? 0 : img.getWidth();
	}
	
	public int getWidth(String str) {
		int width = 0;
		for (char ch: str.toCharArray()) {
			width += getImage(ch).getWidth();
		}
		return width;
	}
	
	public int getHeight(char ch) {
		BufferedImage img = getImage(ch);
		return (img == null) ? 0 : img.getHeight();
	}
	
	public int getLineHeight() {
		return lineHeight;
	}
	
	public int getVShadow() {
		return vShadow;
	}

	public int getHShadow() {
		return hShadow;
	}

	public boolean canDisplay(char ch) {
		return font.canDisplay(ch);
	}
	
	private BufferedImage getImage(char ch) {
		BufferedImage img = null;
		if (ch < 256) {
			img = chars[ch];
		} else {
			img = customChars.get(ch);
		}
		if (img == null) {
			img = createImage(ch);
			if (img.getHeight() > lineHeight) {
				lineHeight = img.getHeight();
			}
			customChars.put(ch, img);
		}
		return img;
	}
	
	private BufferedImage createImage(char ch) {
		BufferedImage img = GameImage.createCompatibleImage(1, 1, Transparency.BITMASK);
		
		Graphics2D g2d = (Graphics2D) img.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
		g2d.setFont(font);
		int fw = g2d.getFontMetrics().charWidth(ch);
//		int fh = g2d.getFontMetrics().getHeight();
		int fa = g2d.getFontMetrics().getMaxAscent();
		int fd = g2d.getFontMetrics().getMaxDescent();
		int fl = g2d.getFontMetrics().getLeading();
		g2d.dispose();
		
		
		if (fw <= 0) {
			fw = 1;
		}

		int w = fw + Math.abs(hShadow);
		int h = fa + fl + Math.abs(vShadow);
//		int h = fh;
		
		img = GameImage.createCompatibleImage(w, h, Transparency.BITMASK);
		g2d = (Graphics2D) img.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
		g2d.setBackground(new Color(255, 255, 255, 0));
		g2d.clearRect(0, 0, w, h);
		g2d.setFont(font);

		if (hShadow != 0 || vShadow != 0) {
			int ox = hShadow < 0 ? 0 : hShadow;
			int oy = (fa - fd + fl) + (vShadow < 0 ? 0 : vShadow);
//			int oy = (h - fd + fl) + (vShadow < 0 ? 0 : vShadow);
			g2d.setColor(background);
			g2d.drawString(String.valueOf(ch), ox, oy);
		}

		int ox = hShadow < 0 ? -hShadow : 0;
		int oy = (fa - fd + fl) + (vShadow < 0 ? -vShadow : 0);
//		int oy = (h - fd + fl) + (vShadow < 0 ? -vShadow : 0);

		GradientPaint paint = new GradientPaint(0, 0, foreground[0], 0, h/2, foreground[1], true);
		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		g2d.setPaint(paint);
		g2d.drawString(String.valueOf(ch), ox, oy);
		
		return img;
	}

	private void createImageSet() {
		for (int i = 0; i < 256; i++) {
			char ch = (char) i;
			BufferedImage img = createImage(ch);
			if (img.getHeight() > lineHeight) {
				lineHeight = img.getHeight();
			}
			chars[i] = img;
			img = null;
		}
	}
	
	public void render(Graphics2D g2d, float sx, float sy, char ch) {
		int x = Math.round(sx);
		int y = Math.round(sy);	
		BufferedImage img = getImage(ch);
		g2d.drawImage(img, x, y, null);
	}
	
	public void render(Graphics2D g2d, float sx, float sy, String str) {
		for (char ch: str.toCharArray()) {
			render(g2d, sx, sy, ch);
			sx += getWidth(ch);
		}
	}
	
}
